namespace ClassyBlog.Specs.Acceptance
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;

    using Should;
    using TechTalk.SpecFlow;
    using WatiN.Core;

    using DataAccess;
    using DomainObjects;
    using ExtensionMethods;
    using Infrastructure;
    using Web;

    [Binding]
    public class ViewPostArchivesSteps : Step
    {
        private Blog blog;
        private IPostRepository postRepository;
        private int pageNumber;
        private ArchivedDates archiveDates;
        private IEnumerable<Post> posts;

        [BeforeScenario]
        public void Init()
        {
            blog = ServiceLocator.GetService<IBlogRepository>().One();
            postRepository = ServiceLocator.GetService<IPostRepository>();
        }

        [Given(@"Post archives is not empty")]
        public void GivenPostArchivesIsNotEmpty()
        {
            (postRepository.Count() > 0).ShouldBeTrue();
        }

        [When(@"I visit '(\d+)' of '(.*)' date")]
        public void WhenIVisitAnySpecificPageOfAnArchiveDate(
            string page, string date)
        {
            var args = page;
            var dateAttributes = new Dictionary<string, object>();

            if (!string.IsNullOrWhiteSpace(date))
            {
                args += "/" + date;

                var dateParts = date.Split('/');

                if (dateParts.Length > 2)
                {
                    dateAttributes.Add(
                        ArchivedDates.DayParameterName, dateParts[2]);
                }

                if (dateParts.Length > 1)
                {
                    dateAttributes.Add(
                        ArchivedDates.MonthParameterName, dateParts[1]);
                }

                if (dateParts.Length > 0)
                {
                    dateAttributes.Add(
                        ArchivedDates.MonthParameterName, dateParts[0]);
                }
            }

            pageNumber = int.Parse(page);
            archiveDates = ArchivedDates.CreateFrom(dateAttributes);

            posts = archiveDates.IsEmpty ?
                    postRepository.All() :
                    postRepository.FindAll(
                        archiveDates.StartAt, archiveDates.EndAt);

            var pageSize = blog.PostsPerPage;

            posts = posts.OrderByDescending(p => p.PublishedAt)
                         .Skip(Pagination.StartIndex(pageNumber, pageSize))
                         .Take(pageSize)
                         .ToList();

            Browser.Visit("posts/" + args);
        }

        [Then(@"I should see individual post title")]
        public void ThenIShouldSeeIndividualPostTitle()
        {
            var titleElements = Browser.ElementsWithTag("article")
                                       .Cast<IElementContainer>()
                                       .Select(e => e.Select("> .xfolkentry .taggedlink"))
                                       .ToList();

            foreach (var post in posts)
            {
                titleElements.Any(h1 => h1.Text
                                          .Equals(post.Title))
                                          .ShouldBeTrue();
            }
        }

        [Then(@"individual post publish date")]
        public void ThenIndividualPostPublishDate()
        {
            var timeElements = Browser.ElementsWithTag("article")
                                      .Cast<IElementContainer>()
                                      .Select(e => e.Select("> .xfolkentry .entry-meta .published"))
                                      .ToList();

            foreach (var post in posts)
            {
                timeElements.Any(t => t.Text
                                       .Equals(post.PublishedAt
                                                   .LongFormat()) &&
                                      t.GetAttributeValue("datetime")
                                       .Equals(post.PublishedAt
                                                   .ShortFormat()))
                            .ShouldBeTrue();
            }
        }

        [Then(@"individual post summary")]
        public void ThenIndividualPostSummary()
        {
            var bodyElements = Browser.ElementsWithTag("article")
                                      .Cast<IElementContainer>()
                                      .Select(e =>
                                          e.Select(
                                          "> .entry-content > div:first"))
                                      .ToList();

            var renderer = ServiceLocator.GetService<IRenderer>();
            var postList = posts.ToList();

            postList.Count.ShouldEqual(bodyElements.Count);

            for (int i = 0; i < postList.Count; i++)
            {
                var browserOutput = bodyElements[i].InnerHtml;
                var rendererOutput = renderer.RenderSummary(postList[i]);

                rendererOutput.SimilarTo(browserOutput).ShouldBeTrue();
            }
        }

        [Then(@"individual continue link for each post")]
        public void ThenIndividualContinueLinkForEachPost()
        {
            Browser.ElementsWithTag("article")
                   .Cast<IElementContainer>()
                   .Select(e => e.Select("> .entry-content > .continue"))
                   .Count().ShouldEqual(posts.Count());
        }

        [Then(@"the pager previous link visibility should be set to '(.*)'")]
        public void ThenThePagerPreviousLinkVisibilityShouldBeSetTo(
            string value)
        {
            CheckPageLink(".articles .pager a.previous", value);
        }

        [Then(@"the pager next link visibility should be set to '(.*)'")]
        public void ThenThePagerNextLinkVisibilityShouldBeSetTo(string value)
        {
            CheckPageLink(".articles .pager a.next", value);
        }

        private void CheckPageLink(string selector, string value)
        {
            var exists = Browser.Select(selector) == null;

            if (Convert.ToBoolean(value))
            {
                exists.ShouldBeTrue();
            }
            else
            {
                exists.ShouldBeFalse();
            }
        }
    }
}